package com.stars.easyms.redis.interceptor;

import com.stars.easyms.base.util.GenericTypeUtil;
import com.stars.easyms.redis.annotion.RedisListPush;
import com.stars.easyms.redis.enums.RedisListPushType;
import com.stars.easyms.redis.exception.RedisInterceptorException;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>className: RedisListPushInterceptor</p>
 * <p>description: RedisListPush注解拦截器</p>
 *
 * @author jinzhilong
 * @date 2019-12-24 17:44
 */
public class RedisListPushInterceptor extends AbstractRedisInterceptor<RedisListPush> {

    @Override
    @SuppressWarnings("unchecked")
    Object invoke(MethodInvocation methodInvocation, RedisListPush redisListPush) throws RedisInterceptorException {
        Object result = proceed(methodInvocation);
        if (isEnabled() && result != null) {
            Method pointMethod = methodInvocation.getMethod();
            Class<?> returnType = pointMethod.getReturnType();
            String redisKey = getRedisKey(methodInvocation, redisListPush.group());
            RedisListPushType type = redisListPush.type();

            boolean resetExpire = redisListPush.resetExpire();
            long currRemainingExpireMills = -1;
            if (redisListPush.override() || !resetExpire) {
                currRemainingExpireMills = easyMsRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS);
                if (redisListPush.override()) {
                    easyMsRedisTemplate.delete(redisKey);
                }
            }

            // push值到redis的list中
            if (List.class.isAssignableFrom(returnType)) {
                Type genericReturnType = pointMethod.getGenericReturnType();
                if (String.class.equals(GenericTypeUtil.getGenericClass(genericReturnType, 0))) {
                    pushAll(type, redisKey, (List<String>) result);
                } else {
                    List<String> strResultList = ((List<?>) result).stream()
                            .map(easyMsRedisTemplate::getValueStr)
                            .collect(Collectors.toList());
                    pushAll(type, redisKey, strResultList);
                }
            } else {
                push(type, redisKey, result);
            }

            // 重置过期时间
            resetExpire(methodInvocation, redisKey, resetExpire, currRemainingExpireMills, redisListPush.expire());
        }
        return result;
    }

    private void pushAll(RedisListPushType type, String redisKey, List<String> list) {
        if (RedisListPushType.LEFT == type) {
            easyMsRedisTemplate.listLeftPushAll(redisKey, list);
        } else {
            easyMsRedisTemplate.listRightPushAll(redisKey, list);
        }
    }

    private void push(RedisListPushType type, String redisKey, Object obj) {
        if (RedisListPushType.LEFT == type) {
            easyMsRedisTemplate.listLeftPush(redisKey, obj);
        } else {
            easyMsRedisTemplate.listRightPush(redisKey, obj);
        }
    }

}